package cn.bdqn.bean.json;

import cn.bdqn.format.JSONFormat2Entity;
import com.alibaba.druid.util.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JSONFormat2EntityHandelResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JSONFormat2Entity.class);
    }

    /**
     * 从request的参数中取出JSONFormat2Entity的name属性 并且转换成实体
     *
     * @param parameter     方法参数
     * @param mavContainer
     * @param webRequest    mvc封装的request
     * @param binderFactory
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        JSONFormat2Entity jsonFormat2Entity = parameter.getParameterAnnotation(JSONFormat2Entity.class);//获取注解
        String annotationValue = jsonFormat2Entity.value();//注解的值
        boolean require = jsonFormat2Entity.require();//是否必须的
        String jsonObject = (String) getJSONObject(webRequest);//获取请求参数
        System.out.println(jsonObject);
        String newStr = jsonObject.substring(0, jsonObject.length() - 1).substring(1).replaceAll("\"", "").trim();
        Map<String, Map<String, String>> allParams = parseString2Map(newStr);
        if (require && !allParams.containsKey(annotationValue == null
                ? parameter.getParameterName()
                : annotationValue)) {
            throw new IllegalArgumentException("请求参数中找不到name为:" + annotationValue == null
                    ? parameter.getParameterName()
                    : annotationValue + "的属性!");
        }
        Map<String, String> params = getParamsValue(annotationValue == null
                ? parameter.getParameterName()
                : annotationValue, allParams
        );//通过 注解的value属性来获取 请求参数对象
        Class<?> classType = parameter.getParameterType(); //获取 参数类型3
        return createInstance(classType, params);
    }


    private Object createInstance(Class<?> classType, Map<String, String> params) throws Exception {
        Object obj = classType.newInstance();//创建参数实例
        for (Map.Entry<String, String> entry : params.entrySet()) {//遍历map
            String _key = entry.getKey();//获取key 对应 实体类字段
            String _value = entry.getValue(); //获取值 通过实体类字段 去设置值

            Field field = classType.getDeclaredField(_key);//获取实体类字段
            field.setAccessible(true); //暴力模式 访问 private的属性
            Class<?> type = field.getType();//获取这个 字段的类型 默认都是String
            String fieldType = type.getSimpleName(); // String  //获取这个字段的类型用于类型转换
            field.set(obj, checkType(fieldType, getStringURLEncoding(_value)));
        }
        return obj;
    }

    /**
     * 类型转换
     *
     * @param type
     * @param value
     * @return
     */
    public Object checkType(String type, String value) {
        Object result = null;
        switch (type) {
            case "Integer":
                result = Integer.parseInt(value);
                break;
            case "Date":
                Long stmp = Long.parseLong(value);
                result = new Date(stmp);
                System.out.println(result);
                break;
            case "BigDecimal":
                result = new BigDecimal(value);
                break;
            case "Double":
                result = Double.parseDouble(value);
                break;
            default:
                result = value;
        }

        return result;
    }

    /**
     * 获取请求参数
     *
     * @param webRequest
     * @return
     * @throws Exception
     */
    public Object getJSONObject(NativeWebRequest webRequest) throws Exception {
        String jsonContent = (String) webRequest.getAttribute("", NativeWebRequest.SCOPE_REQUEST);
        if (StringUtils.isEmpty(jsonContent)) {
            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
            BufferedReader bufferReader = request.getReader();
            StringBuffer strBuffer = new StringBuffer();
            char[] buffer = new char[1024];
            int reader;
            while ((reader = bufferReader.read(buffer)) != -1) {
                strBuffer.append(buffer, 0, reader);
            }
            jsonContent = strBuffer.toString();
            if (StringUtils.isEmpty(jsonContent)) {
                Map<String, String[]> params = request.getParameterMap();
                Map<String, Object> temp = new HashMap<>();
                params.forEach((key, value) -> {
                    if (value != null && value.length > 0) {
                        temp.put(key, value);
                    }
                });
            }
            webRequest.setAttribute("", jsonContent, NativeWebRequest.SCOPE_REQUEST);
        }
        return jsonContent;
    }

    private Map<String, Map<String, String>> parseString2Map(String content) {
        String[] entry = content.split(","); //得到所有的js对象
        Map<String, Map<String, String>> map = new HashMap<>();
        for (String string : entry) {
            String[] split = string.split(":");
            map.put(split[0], parseStringURLParams(split[1]));
        }
        return map;
    }

    /**
     * 解析 序列化后的字符串
     *
     * @param content
     * @return
     */
    private Map<String, String> parseStringURLParams(String content) {
        String[] entryStr = content.split("&");
        Map<String, String> params = new HashMap<>();
        for (String str : entryStr) {
            String[] entry = str.split("=");
            params.put(entry[0], entry[1]);
        }
        return params;
    }


    private Map<String, String> getParamsValue(String key, Map<String, Map<String, String>> data) {
        return data.get(key);
    }

    /**
     * 解码(url编码)
     *
     * @param contentEncoding
     * @return
     */
    private String getStringURLEncoding(String contentEncoding) {

        String result = null;
        try {
            if (contentEncoding.contains("%")) {
                result = URLDecoder.decode(contentEncoding, "utf8");//解码
            } else {
                result = contentEncoding;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

}
